import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

public class ChatServer {
    /*
     * This main thread only waits for new connections to the Chatserver socket
     * then delegates each incoming client to a separate thread.
     */
    public static void main(String[] args) {

	if (args.length != 1) {
	    usage();
	    System.exit(1);
	}

	int port = Integer.parseInt(args[0]);
	ConcurrentHashMap<String, ClientsData> clientList = new ConcurrentHashMap<String, ClientsData>();

	// Maintained by all threads and used by Broadcaster thread.
	Broadcaster bcastJob = new Broadcaster(clientList);
	Thread bc = new Thread(bcastJob);
	bc.start();

	ServerSocket serverSocket = null;
	try {
	    serverSocket = new ServerSocket(port);
	} catch (BindException e) {
	    System.out.println("Error: Port already in use.");
	    System.exit(1);
	} catch (IOException e) {
	    e.printStackTrace();
	}

	while (true) {
	    try {
		ClientWorker cw = new ClientWorker(serverSocket.accept(),
			bcastJob, clientList);

		Thread clientThread = new Thread(cw);
		clientThread.start();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}
    }

    public static class ClientsData {
	/*
	 * this class is used for storing necessary information about each user
	 * connected to the chatserver. Each user is represented by and object
	 * of this class which allows for checking whether the user is actively
	 * chatting and which socket he's connected to.
	 */

	// socket established for this client.
	private final Socket socket;
	// nickname of the client.
	private final String nickname;
	// active = this client is a participant in the chat.
	private boolean active;

	public ClientsData(Socket socket, String nickname, boolean active) {
	    this.socket = socket;
	    this.nickname = nickname;
	    this.active = active;
	}

	public Socket getSocket() {
	    return socket;
	}

	public String getNickname() {
	    return nickname;
	}

	public boolean isActive() {
	    return active;
	}

	public void setActive(boolean active) {
	    this.active = active;
	}
    }

    private static void usage() {
	System.out.println("ChatServer port");
    }
}
